<script>
/**
 * 对el-upload进行二次封装，使其支持compressor库并上传压缩后的图片。
 * @property {Object} option compressor的配置，默认值为{ quality: 0.6}，其他配置见官方文档示例。
 *
 * 除了httpRequest和beforeRemove这两个原版的Attribute外，其他的Attribute、Slot、Methods均有效。
 * 本组件是基于el-upload的httpRequest来进行封装的，使用时要注意覆盖默认的上传行为后的一些特性。
 */

import Compressor from 'compressorjs';
import axios from 'axios'

// 保存axios取消请求的构造器
const CancelToken = axios.CancelToken;

export default {
  name: "compressor-upload",
  props: {
    option: {
      type: Object,
      default: () => {
        return {
          quality: 0.6,
        }
      }
    }
  },
  render(h) {
    return h('elUpload', {
      attrs: {
        ...this.$attrs,
        httpRequest: this.uploader,
        beforeRemove: this.handleCancel
      },
      on: {
        ...this.$listeners
      },
      ref: 'upload'
    }, [
      this.$slots.default,
      h('template', {slot: 'trigger'}, this.$slots.trigger),
      h('template', {slot: 'tip'}, this.$slots.tip)
    ])
  },
  data() {
    return {
      // 请求取消方法列表
      cancelList: []
    }
  },
  methods: {
    uploader(h) {
      if (h.file.type.includes('image')) {
        h.onProgress({percent: 0})
        // 创建Compressor实例，用来压缩图片
        new Compressor(h.file, {
          success: (result) => {
            let formData = new FormData()
            let file = new File([result], h.file.name, {type: h.file.type})
            formData.append('file', file)
            axios.post(h.action, formData, {
              onUploadProgress: (e) => {
                let percent = Math.floor((e.loaded * 100) / e.total)
                h.onProgress({percent})
              },
              // 定义此次传输的cancel
              cancelToken: new CancelToken(c => {
                this.cancelList.push({
                  uid: h.file.uid,
                  func: c
                });
              })
            }).then((res) => h.onSuccess(res)).catch(err => h.onError(err))
          },
          error: (err) => {
            h.onError(err)
          },
          // 写入props传递的配置信息
          ...this.option
        })
      } else {
        // 上传的不是图片则拦截此次请求，并且清理el-upload里的uploadFiles
        const unloadIndex = this.$refs.upload.uploadFiles.findIndex((i) => i.uid === h.file.uid)
        this.$refs.upload.uploadFiles.splice(unloadIndex, 1)
        throw new Error('[compressor-upload]: file is not a image')
      }
    },
    handleCancel(file) {
      return this.$confirm(`确定移除 ${file.name}？`).then(() => {
        this.cancelList.find(i => i.uid === file.uid).func()
      })
    },
    clearFiles() {
      this.$refs.upload.clearFiles()
    },
    abort(file) {
      this.$refs.upload.abort(file)
    },
    submit() {
      this.$refs.upload.submit()
    }
  }
}
</script>
